﻿#include <windows.h>    // Windows API头文件，用于串口操作
#include <iostream>     // 输入输出流
#include <vector>       // 向量容器
#include <string>       // 字符串处理
#include <queue>        // 队列容器，用于缓冲数据包
#include <map>          // 映射容器，用于存储指令映射

// 数据帧结构定义
// 使用pragma pack确保结构体字节对齐为1字节，避免编译器自动填充
#pragma pack(push, 1)
typedef struct {
    BYTE header[2];     // 帧头: AA FF
    BYTE deviceId;      // 设备ID: 01
    WORD dataLength;    // 数据长度: 2字节，小端模式 (低字节在前)
    // 注意: 数据部分、校验和和帧尾不包含在结构体中
    // 因为它们的位置和长度是动态的
} DataFrameHeader;
#pragma pack(pop)

// 串口类封装
class SerialPort {
private:
    HANDLE hSerial;         // 串口句柄
    DCB dcbSerialParams;    // 串口参数结构体
    COMMTIMEOUTS timeouts;  // 串口超时设置

public:
    // 构造函数，初始化串口句柄为无效值
    SerialPort() : hSerial(INVALID_HANDLE_VALUE) {}

    // 析构函数，确保串口被正确关闭
    ~SerialPort() {
        if (hSerial != INVALID_HANDLE_VALUE) {
            CloseHandle(hSerial);
        }
    }

    // 打开串口
    bool open(const char* portName, DWORD baudRate = CBR_9600) {
        // 打开串口设备
        // GENERIC_READ | GENERIC_WRITE: 允许读写访问
        // OPEN_EXISTING: 只打开已存在的设备
        hSerial = CreateFileA(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hSerial == INVALID_HANDLE_VALUE) {
            std::cerr << "Error opening serial port " << portName << std::endl;
            return false;
        }

        // 获取当前串口参数
        dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
        if (!GetCommState(hSerial, &dcbSerialParams)) {
            std::cerr << "Error getting comm state" << std::endl;
            return false;
        }

        // 配置串口参数
        dcbSerialParams.BaudRate = baudRate;  // 波特率
        dcbSerialParams.ByteSize = 8;         // 数据位: 8位
        dcbSerialParams.StopBits = ONESTOPBIT;// 停止位: 1位
        dcbSerialParams.Parity = NOPARITY;    // 校验位: 无

        // 应用串口参数
        if (!SetCommState(hSerial, &dcbSerialParams)) {
            std::cerr << "Error setting comm state" << std::endl;
            return false;
        }

        // 配置串口超时设置
        timeouts.ReadIntervalTimeout = 50;            // 字符间超时
        timeouts.ReadTotalTimeoutConstant = 50;       // 读取固定超时
        timeouts.ReadTotalTimeoutMultiplier = 10;     // 读取每字节超时
        timeouts.WriteTotalTimeoutConstant = 50;      // 写入固定超时
        timeouts.WriteTotalTimeoutMultiplier = 10;    // 写入每字节超时

        // 应用超时设置
        if (!SetCommTimeouts(hSerial, &timeouts)) {
            std::cerr << "Error setting timeouts" << std::endl;
            return false;
        }

        std::cout << "Serial port " << portName << " opened successfully" << std::endl;
        return true;
    }

    // 从串口读取数据
    int readData(BYTE* buffer, int bufferSize) {
        DWORD bytesRead;  // 实际读取的字节数
        // 读取串口数据
        if (!ReadFile(hSerial, buffer, bufferSize, &bytesRead, NULL)) {
            std::cerr << "Error reading from serial port" << std::endl;
            return -1;  // 返回-1表示错误
        }
        return bytesRead;  // 返回实际读取的字节数
    }

    // 向串口写入数据
    bool writeData(const BYTE* buffer, DWORD bufferSize) {
        DWORD bytesWritten;  // 实际写入的字节数
        // 写入数据到串口
        if (!WriteFile(hSerial, buffer, bufferSize, &bytesWritten, NULL)) {
            std::cerr << "Error writing to serial port" << std::endl;
            return false;  // 写入失败
        }
        return bytesWritten == bufferSize;  // 返回是否所有数据都已写入
    }

    // 检查串口是否已打开
    bool isOpen() const {
        return hSerial != INVALID_HANDLE_VALUE;
    }
};

// 计算校验和 (简单求和取模)
// 参数: data - 数据指针, length - 数据长度
// 返回: 校验和字节
BYTE calculateChecksum(const BYTE* data, size_t length) {
    DWORD sum = 0;  // 使用DWORD防止溢出
    for (size_t i = 0; i < length; i++) {
        sum += data[i];  // 累加所有字节
    }
    return (BYTE)(sum % 256);  // 取模得到校验和
}

// 打包数据函数
// 参数: rawData - 原始数据指针, rawDataLength - 原始数据长度, deviceId - 设备ID(默认为0x01)
// 返回: 打包后的数据向量
std::vector<BYTE> packageData(const BYTE* rawData, int rawDataLength, BYTE deviceId = 0x01) {
    std::vector<BYTE> packagedData;  // 创建向量存储打包后的数据

    // 添加帧头: AA FF
    packagedData.push_back(0xAA);
    packagedData.push_back(0xFF);

    // 添加设备ID
    packagedData.push_back(deviceId);

    // 添加数据长度 (小端模式: 低字节在前)
    packagedData.push_back(static_cast<BYTE>(rawDataLength & 0xFF));        // 低字节
    packagedData.push_back(static_cast<BYTE>((rawDataLength >> 8) & 0xFF)); // 高字节

    // 添加原始数据
    for (int i = 0; i < rawDataLength; i++) {
        packagedData.push_back(rawData[i]);
    }

    // 计算并添加校验和 (从设备ID开始到原始数据结束)
    // 注意: 校验和计算范围不包括帧头和帧尾
    BYTE checksum = calculateChecksum(packagedData.data() + 2, packagedData.size() - 2);
    packagedData.push_back(checksum);

    // 添加帧尾: 0D 0A
    packagedData.push_back(0x0D);
    packagedData.push_back(0x0A);

    return packagedData;  // 返回打包后的数据
}

// 定义8种不同的指令
const std::vector<std::vector<BYTE>> COMMANDS = {
    {0x01, 0x02, 0x03, 0x04},  // 指令1
    {0x05, 0x06, 0x07, 0x08},  // 指令2
    {0x09, 0x0A, 0x0B, 0x0C},  // 指令3
    {0x0D, 0x0E, 0x0F, 0x10},  // 指令4
    {0x11, 0x12, 0x13, 0x14},  // 指令5
    {0x15, 0x16, 0x17, 0x18},  // 指令6
    {0x19, 0x1A, 0x1B, 0x1C},  // 指令7
    {0x1D, 0x1E, 0x1F, 0x20}   // 指令8
};

// 主函数
int main() {
    SerialPort com1, com2, com5, com6;  // 创建四个串口对象

    // 打开串口1 (接收数据)
    if (!com1.open("COM1", CBR_9600)) {
        std::cerr << "Failed to open COM1" << std::endl;
        return 1;  // 程序异常退出
    }

    // 打开串口2 (发送数据)
    if (!com2.open("COM2", CBR_9600)) {
        std::cerr << "Failed to open COM2" << std::endl;
        return 1;  // 程序异常退出
    }

    // 打开串口5 (接收控制指令)
    if (!com5.open("COM5", CBR_9600)) {
        std::cerr << "Failed to open COM5" << std::endl;
        return 1;  // 程序异常退出
    }

    // 打开串口6 (发送指令)
    if (!com6.open("COM6", CBR_9600)) {
        std::cerr << "Failed to open COM6" << std::endl;
        return 1;  // 程序异常退出
    }

    std::cout << "Starting data transmission..." << std::endl;
    std::cout << "Data will be buffered and sent in batches of 1400 bytes" << std::endl;
    std::cout << "COM5 can receive control commands (0-7) to send different instructions via COM6" << std::endl;

    BYTE receiveBuffer[1024];        // 接收数据缓冲区
    BYTE commandBuffer[64];          // 命令接收缓冲区
    std::vector<BYTE> sendBuffer;    // 发送数据缓冲区，用于累积打包后的数据

    // 主循环
    while (true) {
        // 1. 从串口1读取数据并打包
        int bytesRead = com1.readData(receiveBuffer, sizeof(receiveBuffer));

        if (bytesRead > 0) {
            // 成功读取到数据
            std::cout << "Received " << bytesRead << " bytes from COM1" << std::endl;

            // 打包数据
            std::vector<BYTE> packagedData = packageData(receiveBuffer, bytesRead);

            // 将打包后的数据添加到发送缓冲区
            sendBuffer.insert(sendBuffer.end(), packagedData.begin(), packagedData.end());

            std::cout << "Packaged data size: " << packagedData.size() << " bytes" << std::endl;
            std::cout << "Total buffered data: " << sendBuffer.size() << " bytes" << std::endl;

            // 检查是否达到发送阈值(1400字节)
            if (sendBuffer.size() >= 1400) {
                // 通过串口2发送缓冲区的数据
                if (com2.writeData(sendBuffer.data(), static_cast<DWORD>(sendBuffer.size()))) {
                    std::cout << "Sent " << sendBuffer.size() << " bytes to COM2" << std::endl;

                    // 清空发送缓冲区
                    sendBuffer.clear();
                }
                else {
                    std::cerr << "Failed to send data to COM2" << std::endl;
                }
            }
        }
        else if (bytesRead < 0) {
            // 读取数据出错
            std::cerr << "Error reading from COM1" << std::endl;
        }

        // 2. 从串口5读取控制指令
        int commandBytes = com5.readData(commandBuffer, sizeof(commandBuffer));

        if (commandBytes > 0) {
            std::cout << "Received " << commandBytes << " command bytes from COM5" << std::endl;

            // 处理每个接收到的命令字节
            for (int i = 0; i < commandBytes; i++) {
                BYTE cmd = commandBuffer[i];

                // 检查命令是否有效 (0-7)
                if (cmd >= 0 && cmd <= 7) {
                    std::cout << "Executing command: " << static_cast<int>(cmd) << std::endl;

                    // 通过串口6发送对应的指令
                    const std::vector<BYTE>& selectedCommand = COMMANDS[cmd];
                    if (com6.writeData(selectedCommand.data(), static_cast<DWORD>(selectedCommand.size()))) {
                        std::cout << "Sent command " << static_cast<int>(cmd)
                            << " (" << selectedCommand.size() << " bytes) to COM6" << std::endl;
                    }
                    else {
                        std::cerr << "Failed to send command to COM6" << std::endl;
                    }
                }
                else {
                    std::cerr << "Invalid command received: " << static_cast<int>(cmd) << std::endl;
                }
            }
        }
        else if (commandBytes < 0) {
            // 读取命令出错
            std::cerr << "Error reading from COM5" << std::endl;
        }

        // 短暂休眠以减少CPU占用
        Sleep(10);
    }

    // 程序退出前，检查是否还有未发送的数据
    if (!sendBuffer.empty()) {
        std::cout << "Sending remaining " << sendBuffer.size() << " bytes before exit..." << std::endl;
        com2.writeData(sendBuffer.data(), static_cast<DWORD>(sendBuffer.size()));
    }

    return 0;  // 程序正常退出
}